package com.duguo.dynamicmvc.factory.stage;

import java.util.List;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import com.duguo.dynamicmvc.factory.ControllerBuilder;
import com.duguo.dynamicmvc.factory.ControllerFactory;
import com.duguo.dynamicmvc.factory.WorkingModel;
import com.duguo.dynamicmvc.factory.processor.ProcessorHolder;
import com.duguo.dynamicmvc.factory.processor.controller.ControllerNameBuilder;
import com.duguo.dynamicmvc.factory.processor.controller.ControllerProcessor;
import com.duguo.dynamicmvc.factory.processor.register.RegisterProcessor;
import com.duguo.dynamicmvc.factory.processor.view.ViewProcessor;
import com.duguo.dynamicmvc.factory.utils.BeanUtils;
import com.duguo.dynamicmvc.factory.utils.javassist.FieldUtils;

public class RegisterMethodControllersStage implements Stage {

    public void execute(ControllerFactory controllerFactory) throws Exception {
        WorkingModel workingModel = controllerFactory.getWorkingModel();
        ControllerBuilder controllerBuilder = controllerFactory.getControllerBuilder();
		ProcessorHolder processorHolder = controllerBuilder.getProcessorHolder();
		ControllerProcessor controllerProcessor = processorHolder.getControllerProcessor();
		CtClass controllerCtClass = workingModel.getControllerCtClass();
		List<CtMethod> methodControllers=controllerProcessor.getControllerMethods(controllerCtClass);
        ViewProcessor viewProcessor = processorHolder.getViewProcessor();
        ControllerNameBuilder controllerNameBuilder = controllerProcessor.getControllerNameBuilder();
        
        RegisterProcessor registerProcessor = processorHolder.getRegisterProcessor();
        for (CtMethod controllerMethodCtMethod : methodControllers) {
			Object controllerInstance = workingModel.getControllerInstance();
			Object controller = createInternalMethodController(workingModel, controllerMethodCtMethod, controllerBuilder, 
					viewProcessor, controllerNameBuilder, controllerProcessor, controllerInstance,controllerCtClass);
			String controllerName=viewProcessor.getControllerName(controllerMethodCtMethod);
			registerProcessor.registerControllerBean(controllerInstance, controllerName, controller);
        }
    }


    private Object createInternalMethodController(WorkingModel workingModel, CtMethod controllerMethodCtMethod, ControllerBuilder controllerBuilder,
    		ViewProcessor viewProcessor, ControllerNameBuilder controllerNameBuilder, ControllerProcessor controllerProcessor, Object controllerInstance, CtClass controllerCtClass) throws Exception {
        String methodControllerName=controllerNameBuilder.getControllerInternalClassName(
        		controllerCtClass.getName(), controllerMethodCtMethod.getName(), true);
    	CtClass internalControllerClass = ClassPool.getDefault().makeClass(methodControllerName);
        internalControllerClass.addInterface(workingModel.getInternalHandlerInterfaceCtClass());

        FieldUtils.setupField(internalControllerClass, controllerCtClass, "controller");
        FieldUtils.setupField(internalControllerClass, controllerProcessor.getViewCtClass(), "view");

        controllerProcessor.createInternalMethodControllerHandlerMethod(workingModel, internalControllerClass, controllerMethodCtMethod,controllerBuilder);
        Object ctrlInstance = internalControllerClass.toClass().newInstance();
        BeanUtils.setFieldValue(ctrlInstance, "controller", controllerInstance);
        
        viewProcessor.bindView(ctrlInstance,workingModel.getControllerPath(),workingModel.getStaticViewMapping(),
        		controllerMethodCtMethod, workingModel.isSingleActionController());
        return ctrlInstance;
    }

}
